home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / quicktime vr / vrscript / feature files / vrmovies.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  41.1 KB  |  1,486 lines

  1. //////////
  2. //
  3. //    File:        VRMovies.c
  4. //
  5. //    Contains:    Support for QuickTime movie playback in VR nodes.
  6. //
  7. //    Written by:    Tim Monroe
  8. //                Some code borrowed from QTVRSamplePlayer by Bryce Wolfson.
  9. //
  10. //    Copyright:    © 1996-1998 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):VRMoov_LoadEmbeddedMovie
  13. //
  14. //       <29>         06/30/99    rtm        added fix to VRMoov_LoadEmbeddedMovie to call VRMoov_SetOneBalanceAndVolume
  15. //                                    only for localized sounds
  16. //       <28>         06/29/99    rtm        reworked VRMoov_LoopEmbeddedMovie to support palindrome looping
  17. //       <27>         06/24/99    rtm        major overhaul of geometry handling, using newly-revised code from
  18. //                                    VRMovies project; removed USE_COPYBITS_TO_BACKBUFFER flag, since we now
  19. //                                    always use DecompressSequenceS
  20. //       <26>         05/17/99    rtm        reworked geometry handling to support horizontal back buffer in QT 4.0,
  21. //                                    using code from revised VRMovies project; this code now automatically
  22. //                                    determines whether the back buffer is oriented horizontally or not and
  23. //                                    then does the right thing in either case
  24. //       <25>         04/07/99    rtm        revised VRMoov_StartMovie
  25. //       <24>         03/29/99    rtm        added VRMoov_Init and VRMoov_Stop; conditionalized out the support for
  26. //                                    on-the-fly movie rotation (too many problems reported)
  27. //       <23>         03/29/99    rtm        added VRMoov_StartMovie as a wrapper for StartMovie to handle streamed
  28. //                                    movies; changed StartMovie to VRMoov_StartMovie passim
  29. //       <22>         01/26/99    rtm        changed two occurrences of gw->portPixMap to GetGWorldPixMap(gw)
  30. //       <21>        12/03/98    rtm        modified VRMoov_LoadEmbeddedMovie to accept a string as a parameter,
  31. //                                    which can now be a full URL or a pathname
  32. //       <20>        09/28/98    rtm        added call to DisposeMovie in VRMoov_PlayTransitionMovie to plug leak
  33. //       <19>        09/11/98    rtm        added code to use DecompressImage instead of CopyBits when copying
  34. //                                    an embedded movie frame into the backbuffer; set the compiler flag
  35. //                                    USE_COPYBITS_TO_BACKBUFFER in VRMovies.h to select the desired call
  36. //       <18>        05/04/98    rtm        added support for on-the-fly movie rotation
  37. //       <17>        05/01/98    rtm        added VRMoov_DoIdle call to VRMoov_PlayTransitionMovie, to service
  38. //                                    scene-wide sounds while a transition movie is playing; also added
  39. //                                    call to FlushEvents and cleaned up surrounding code
  40. //       <16>        10/29/97    rtm        modified VRMoov_SetVideoGraphicsMode to use GetMovieIndTrackType
  41. //       <15>         09/18/97    rtm        added parameter to VRMoov_CheckForCompletedMovies
  42. //       <14>         06/24/97    rtm        modified VRMoov_DoIdle to service QuickTime movies with video tracks 
  43. //                                    in non-frontmost windows
  44. //       <13>         06/19/97    rtm        added support for scene-wide sound-only movies
  45. //       <12>         05/13/97    rtm        added VRMoov_PlayTransitionMovie
  46. //       <11>         04/28/97    rtm        reworked to support sound-only movie files as well
  47. //       <10>         04/28/97    rtm        added VRMoov_PlayMovie; reworked passim to use linked list
  48. //       <9>         03/17/97    rtm        added VRMoov_SetMovieBalanceAndVolume
  49. //       <8>         03/12/97    rtm        copied file from VRMovies project and integrated with VRScript
  50. //       <7>         03/06/97    rtm        started to implement video masking
  51. //       <6>         03/05/97    rtm        added VRMoov_SetChromaColor; added fChromaColor to app data record
  52. //       <5>         03/04/97    rtm        fixed compositing problems at back buffer edges
  53. //       <4>         03/03/97    rtm        added VRMoov_SetVideoGraphicsMode to handle compositing
  54. //                                    without using an offscreen GWorld
  55. //       <3>         02/27/97    rtm        further development: borrowed some ideas from QTVRSamplePlayer;
  56. //                                    added VRMoov_SetEmbeddedMovieWidth etc.
  57. //       <2>         12/12/96    rtm        further development: borrowed some ideas from BoxMoov demo 
  58. //       <1>         12/11/96    rtm        first file 
  59. //       
  60. // This code supports playing QuickTime movies in QTVR panoramas. For movies with video tracks,
  61. // this code draws the QuickTime movie frames into the back buffer, either directly or indirectly
  62. // (via an offscreen GWorld). Direct drawing gives the best performance, but indirect drawing is
  63. // necessary for some visual effects. 
  64. //
  65. //////////
  66.  
  67. // TO DO:
  68. // + finish video masking by custom 'hide' hot spots (so video goes *behind* such hot spots)
  69. // + verify that everything works okay if *images* are used instead of movies (scaling seems to be a problem)
  70.  
  71.  
  72. //////////
  73. //       
  74. // header files
  75. //       
  76. //////////
  77.  
  78. #include "VRMovies.h"
  79. #include "VRScript.h"
  80.  
  81.  
  82. //////////
  83. //       
  84. // constants
  85. //       
  86. //////////
  87.  
  88. const RGBColor                    kBlackColor = {0x0000, 0x0000, 0x0000};        // black
  89. const RGBColor                    kWhiteColor = {0xffff, 0xffff, 0xffff};        // white
  90.  
  91.  
  92. //////////
  93. //       
  94. // global variables
  95. //       
  96. //////////
  97.  
  98. MoviePrePrerollCompleteUPP        gMoviePPRollCompleteProc = NULL;            // a routine descriptor for our pre-preroll completion routine
  99.  
  100.  
  101. //////////
  102. //
  103. // VRMoov_Init
  104. // Initialize for QuickTime movie playback.
  105. //
  106. //////////
  107.  
  108. void VRMoov_Init (void)
  109. {
  110.     // allocate a routine descriptor for our pre-preroll completion routine
  111.     if (gMoviePPRollCompleteProc == NULL)
  112.         gMoviePPRollCompleteProc = NewMoviePrePrerollCompleteProc(VRScript_MoviePrePrerollCompleteProc);
  113. }
  114.  
  115.  
  116. //////////
  117. //
  118. // VRMoov_Stop
  119. // Close down for QuickTime movie playback.
  120. //
  121. //////////
  122.  
  123. void VRMoov_Stop (void)
  124. {
  125.     // deallocate routine descriptor
  126.     if (gMoviePPRollCompleteProc != NULL)
  127.         DisposeRoutineDescriptor(gMoviePPRollCompleteProc);
  128. }
  129.  
  130.  
  131. //////////
  132. //
  133. // VRMoov_StartMovie
  134. // Start a QuickTime movie playing.
  135. //
  136. // This is essentially just a wrapper for StartMovie, to handle preprerolling of streamed movies.
  137. //
  138. //////////
  139.  
  140. void VRMoov_StartMovie (Movie theMovie)
  141. {    
  142.     PrePrerollMovie(theMovie, 0, GetMoviePreferredRate(theMovie), gMoviePPRollCompleteProc, (void *)0L);
  143. }
  144.  
  145.  
  146. //////////
  147. //
  148. // VRMoov_PlayMovie
  149. // Start a QuickTime movie playing or stop one from playing.
  150. //
  151. //////////
  152.  
  153. void VRMoov_PlayMovie (
  154.                 WindowObject theWindowObject,
  155.                 UInt32 theNodeID,
  156.                 UInt32 theEntryID, 
  157.                 float thePanAngle,
  158.                 float theTiltAngle,
  159.                 float theScale, 
  160.                 float theWidth, 
  161.                 UInt32 theKeyRed, 
  162.                 UInt32 theKeyGreen, 
  163.                 UInt32 theKeyBlue, 
  164.                 Boolean theUseBuffer,
  165.                 Boolean theUseCenter,
  166.                 Boolean theUseKey,
  167.                 Boolean theUseHide,
  168.                 Boolean theUseDir,
  169.                 Boolean theRotate,
  170.                 float theVolAngle,
  171.                 UInt32 theMode,
  172.                 UInt32 theOptions,
  173.                 char *thePathName)
  174. {
  175.     ApplicationDataHdl        myAppData;
  176.     Boolean                    myNeedPlayMovie = false;
  177.     Boolean                    myNeedLoadMovie = false;
  178.     VRScriptMoviePtr        myPointer = NULL;
  179.     
  180.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  181.     if (myAppData == NULL)
  182.         return;
  183.     
  184.     // see if this movie is already in our list of playing movies                
  185.     myPointer = (VRScriptMoviePtr)VRScript_GetObjectByEntryID(theWindowObject, kVREntry_QTMovie, theEntryID);
  186.         
  187.     if (myPointer == NULL) {
  188.         // this movie isn't in our list yet, so we'll need to add it to the list
  189.         myNeedLoadMovie = true;
  190.         myNeedPlayMovie = true;
  191.     } else {
  192.         // this movie is already in our list; theOptions determines how we handle this request:
  193.         
  194.         switch (theOptions) {
  195.         
  196.             case kVRMedia_PlayNew:
  197.                 // start the movie playing (whether it's already playing or not);
  198.                 // multiple movies aren't supported in QTVR 2.0, so we just map to kVRMedia_Continue
  199.                 myNeedPlayMovie = true;
  200.                 myNeedLoadMovie = true;
  201.                 break;
  202.                 
  203.             case kVRMedia_Restart:
  204.                 // stop the current movie and then restart it; use the existing movie data
  205.                 StopMovie(myPointer->fMovie);
  206.                 myNeedPlayMovie = true;
  207.                 myNeedLoadMovie = false;
  208.                 break;
  209.                 
  210.             case kVRMedia_ToggleStop:
  211.                 // toggle the movie's current play/stop state
  212.                 myNeedLoadMovie = false;
  213.                 if (!IsMovieDone(myPointer->fMovie)) {
  214.                     // stop the movie and get rid of movie list entry
  215.                     StopMovie(myPointer->fMovie);
  216.                     VRScript_DelistEntry(theWindowObject, (VRScriptGenericPtr)myPointer);
  217.                     myNeedPlayMovie = false;
  218.                 } else {
  219.                     // start the movie; use the existing movie data
  220.                     myNeedPlayMovie = true;
  221.                 }
  222.                 break;
  223.                 
  224.             case kVRMedia_TogglePause:
  225.                 // toggle the movie's current play/pause state
  226.                 myNeedLoadMovie = false;
  227.                 if (GetMovieRate(myPointer->fMovie) != (Fixed)0) {
  228.                     // stop the movie
  229.                     StopMovie(myPointer->fMovie);
  230.                     myNeedPlayMovie = false;
  231.                 } else {
  232.                     // restart the movie; use the existing movie data
  233.                     myNeedPlayMovie = false;
  234.                     StartMovie(myPointer->fMovie);
  235.                 }
  236.                 break;
  237.                 
  238.             case kVRMedia_Continue:
  239.                 // just let the movie already in progress continue
  240.                 myNeedPlayMovie = false;
  241.                 myNeedLoadMovie = false;
  242.                 break;
  243.                 
  244.             case kVRMedia_Stop:
  245.                 // stop the current movie
  246.                 StopMovie(myPointer->fMovie);
  247.                 myNeedPlayMovie = false;
  248.                 myNeedLoadMovie = false;
  249.                 break;
  250.                 
  251.             default:
  252.                 // unrecognized option
  253.                 // start the movie playing
  254.                 myNeedPlayMovie = true;
  255.                 myNeedLoadMovie = false;
  256.                 break;
  257.         }
  258.     }
  259.     
  260.     if (myNeedLoadMovie) {
  261.         myPointer = VRScript_EnlistMovie (
  262.                         theWindowObject,
  263.                         theNodeID, 
  264.                         theEntryID,
  265.                         thePanAngle,
  266.                         theTiltAngle,
  267.                         theScale, 
  268.                         theWidth, 
  269.                         theKeyRed, 
  270.                         theKeyGreen, 
  271.                         theKeyBlue, 
  272.                         theUseBuffer,
  273.                         theUseCenter,
  274.                         theUseKey,
  275.                         theUseHide,
  276.                         theUseDir,
  277.                         theRotate,
  278.                         theVolAngle,
  279.                         theMode,
  280.                         theOptions,
  281.                         thePathName);
  282.     }
  283.  
  284.     if (myNeedPlayMovie)
  285.         if (myPointer != NULL)
  286.             VRMoov_LoadEmbeddedMovie(thePathName, theWindowObject, myPointer);
  287. }
  288.  
  289.  
  290. //////////
  291. //
  292. // VRMoov_PlayTransitionMovie
  293. // Play a QuickTime movie as a transition from one node to another.
  294. //
  295. //////////
  296.  
  297. void VRMoov_PlayTransitionMovie (WindowObject theWindowObject, UInt32 theOptions, char *thePathName)
  298. {
  299.     FSSpec        myFSSpec;
  300.     short        myMovieFileRef = 0;
  301.     Movie        myMovie;
  302.     Rect        myRect;
  303.     GWorldPtr    myGWorld;
  304.     GDHandle    myGDevice;
  305.     long        myCount = 0;
  306.     Boolean        myUserCancelled = false;
  307.     OSErr        myErr = noErr;
  308.     
  309.     if ((theWindowObject == NULL) || (thePathName == NULL))
  310.         goto bail;
  311.         
  312.     FileUtils_MakeFSSpecForPathName(0, 0L, thePathName, &myFSSpec);
  313.     
  314.     // open the movie
  315.     myErr = OpenMovieFile(&myFSSpec, &myMovieFileRef, fsRdPerm);
  316.     if (myErr != noErr)
  317.         goto bail;
  318.  
  319.     myErr = NewMovieFromFile(&myMovie, myMovieFileRef, NULL, NULL, newMovieActive, NULL);
  320.     if ((myErr != noErr) || (myMovie == NULL))
  321.         goto bail;
  322.  
  323.     // set the movie GWorld
  324.     GetMovieGWorld((**theWindowObject).fMovie, &myGWorld, &myGDevice);
  325.     SetMovieGWorld(myMovie, myGWorld, myGDevice);
  326.             
  327.     // set the movie box to the size of the QTVR window            
  328.     GetMovieBox((**theWindowObject).fMovie, &myRect);    
  329.     SetMovieBox(myMovie, &myRect);
  330.     
  331.     // start the movie
  332.     GoToBeginningOfMovie(myMovie);
  333.     VRMoov_StartMovie(myMovie);
  334.     
  335.     // play the movie once thru
  336.     while (!IsMovieDone(myMovie) && !myUserCancelled) {
  337.         MoviesTask(myMovie, 0);
  338.         SystemTask();
  339.         
  340.         // on very long transition movies (or very slow machines), scene-wide sound-only movies need to be serviced
  341.         // (but not every time thru the loop, eh?)
  342.         if (myCount % kDoIdleStep == 0)
  343.             VRMoov_DoIdle(theWindowObject);
  344.             
  345.         myCount++;
  346.         
  347.         // see if the user has cancelled the transition movie, if so allowed
  348.         if (theOptions == kVRMovie_PlayTilClick)
  349.             myUserCancelled = Button();
  350.     }
  351.     
  352.     StopMovie(myMovie);
  353.     DisposeMovie(myMovie);
  354.     
  355.     // button clicks during a transition movie remain in the OS event queue (even if detected by the
  356.     // Button call above); we'd better remove them (by calling FlushEvents) or they may trigger a hot
  357.     // spot in the destination node; note that if theOptions is kVRMovie_PlayTilClick, then the first
  358.     // click stops the movie and gets flushed, but any subsequent clicks remain in the OS event queue
  359.     // and get processed normally....
  360.     FlushEvents(mDownMask + mUpMask, 0);
  361.     
  362. bail:
  363.     if (myMovieFileRef != 0)
  364.         CloseMovieFile(myMovieFileRef);
  365. }
  366.  
  367.  
  368. //////////
  369. //
  370. // VRMoov_LoadEmbeddedMovie
  371. // Load the QuickTime movie in the specified file.
  372. // Returns a Boolean to indicate success (true) or failure (false).
  373. //
  374. //////////
  375.  
  376. Boolean VRMoov_LoadEmbeddedMovie (char *thePathName, WindowObject theWindowObject, VRScriptMoviePtr theEntry)
  377. {
  378.     FSSpec                    myFSSpec;
  379.     short                    myMovieFileRef = 0;
  380.     Movie                    myMovie = NULL;
  381.     GWorldPtr                myGWorld = NULL;
  382.     Rect                    myRect;
  383.     ApplicationDataHdl        myAppData = NULL;
  384.     QTVRInstance            myInstance = NULL;
  385.     OSErr                    myErr = paramErr;
  386.  
  387.     //////////
  388.     //
  389.     // validate the window object and application data
  390.     //
  391.     //////////
  392.  
  393.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  394.     if (myAppData == NULL)
  395.         goto bail;
  396.         
  397.     if (theEntry == NULL)
  398.         goto bail;
  399.         
  400.     myInstance = (**theWindowObject).fInstance;
  401.     if (myInstance == NULL)
  402.         goto bail;
  403.         
  404.     HLock((Handle)myAppData);
  405.  
  406.     //////////
  407.     //
  408.     // open the movie file and the movie
  409.     //
  410.     //////////
  411.     
  412.     if (URLUtils_IsAbsoluteURL(thePathName)) {
  413.         // we were passed a URL
  414.         myMovie = URLUtils_NewMovieFromURL(thePathName, newMovieActive, NULL);
  415.         if (myMovie == NULL)
  416.             goto bail;
  417.     } else {
  418.         // we were passed a filename; create an FSSpec for the file
  419.         FileUtils_MakeFSSpecForPathName(0, 0L, thePathName, &myFSSpec);
  420.         
  421.         // open the movie
  422.         myErr = OpenMovieFile(&myFSSpec, &myMovieFileRef, fsRdPerm);
  423.         if (myErr != noErr)
  424.             goto bail;
  425.  
  426.         myErr = NewMovieFromFile(&myMovie, myMovieFileRef, NULL, (StringPtr)NULL, newMovieActive, NULL);
  427.         if (myErr != noErr)
  428.             goto bail;
  429.     }
  430.  
  431.     //////////
  432.     //
  433.     // get the movie geometry
  434.     //
  435.     //////////
  436.  
  437.     GetMovieBox(myMovie, &myRect);
  438.     GetMovieMatrix(myMovie, &theEntry->fOrigMovieMatrix);
  439.     MacOffsetRect(&myRect, -myRect.left, -myRect.top);
  440.     SetMovieBox(myMovie, &myRect);
  441.     
  442.     // determine the orientation of the back buffer
  443.      (**myAppData).fBackBufferIsHoriz = QTVRUtils_IsBackBufferHorizontal((**theWindowObject).fInstance);
  444.      (**myAppData).fBackBufferIsHoriz = false;
  445.  
  446.     // keep track of the movie and movie rectangle
  447.     theEntry->fMovie = myMovie;
  448.     theEntry->fMovieBox = myRect;
  449.     
  450.     //////////
  451.     //
  452.     // determine what kinds of media are in this movie
  453.     //
  454.     //////////
  455.  
  456.     theEntry->fQTMovieHasSound = QTUtils_IsMediaTypeInMovie(myMovie, SoundMediaType) || QTUtils_IsMediaTypeInMovie(myMovie, MusicMediaType);
  457.     theEntry->fQTMovieHasVideo = QTUtils_IsMediaTypeInMovie(myMovie, VideoMediaType);
  458.  
  459.     //////////
  460.     //
  461.     // do processing for video media
  462.     //
  463.     //////////
  464.  
  465.     if (theEntry->fQTMovieHasVideo) {
  466.         // get rid of any existing offscreen graphics world
  467.         if (theEntry->fOffscreenGWorld != NULL) {
  468.             UnlockPixels(theEntry->fOffscreenPixMap);
  469.             DisposeGWorld(theEntry->fOffscreenGWorld);
  470.             theEntry->fOffscreenGWorld = NULL;
  471.         }
  472.     
  473.         // clear out any existing custom cover function and reset the video media graphics mode
  474.         // (these may have been modified for direct-screen drawing)
  475.         SetMovieCoverProcs(myMovie, NULL, NULL, 0);
  476.         VRMoov_SetVideoGraphicsMode(myMovie, theEntry, false);
  477.         
  478.         // if necessary, create an offscreen graphics world;
  479.         // this is where we'll image the movie before copying it into the back buffer
  480.         // when we want to do special effects
  481.         if (theEntry->fUseOffscreenGWorld) {
  482.             myErr = NewGWorld(&myGWorld, 0, &myRect, NULL, NULL, 0);
  483.             theEntry->fOffscreenGWorld = myGWorld;
  484.             theEntry->fOffscreenPixMap = GetGWorldPixMap(myGWorld);
  485.             
  486.             // make an image description, which is needed by DecompressSequenceBegin
  487.             LockPixels(theEntry->fOffscreenPixMap);
  488.             MakeImageDescriptionForPixMap(theEntry->fOffscreenPixMap, &(theEntry->fImageDesc));
  489.             UnlockPixels(theEntry->fOffscreenPixMap);
  490.         } else {
  491.             // set the video media graphics mode to drop out the chroma key color in a movie;
  492.             // we also need to install an uncover function that doesn't erase the uncovered region
  493.             if (theEntry->fCompositeMovie) {
  494.                 VRMoov_SetVideoGraphicsMode(myMovie, theEntry, true);
  495.                 SetMovieCoverProcs(myMovie, NewMovieRgnCoverProc(VRMoov_CoverProc), NULL, (long)theWindowObject);
  496.             }
  497.         }
  498.     }
  499.     
  500.     //////////
  501.     //
  502.     // do processing for sound media
  503.     //
  504.     //////////
  505.  
  506.     if (theEntry->fQTMovieHasSound) {
  507.         // get the sound media handler
  508.         theEntry->fMediaHandler = QTUtils_GetSoundMediaHandler(myMovie);
  509.  
  510.         // set initial balance and volume
  511.         if (theEntry->fSoundIsLocalized) {
  512.             VRMoov_SetOneBalanceAndVolume(myMovie, theEntry->fMediaHandler, QTVRGetPanAngle(myInstance), QTVRGetTiltAngle(myInstance), theEntry->fMovieCenter.x, theEntry->fVolAngle);
  513.             (**myAppData).fSoundHasChanged = true;
  514.         }
  515.     }
  516.         
  517.     //////////
  518.     //
  519.     // install the back-buffer imaging procedure
  520.     //
  521.     //////////
  522.     
  523.     if ((**theWindowObject).fInstance != NULL)
  524.         VRScript_InstallBackBufferImagingProc((**theWindowObject).fInstance, theWindowObject);
  525.         
  526.     //////////
  527.     //
  528.     // start the movie playing
  529.     //
  530.     //////////
  531.  
  532.     if (theEntry->fMode == kVRPlay_Loop) {
  533.         // start the movie playing in a loop
  534.         VRMoov_LoopEmbeddedMovie(myMovie, false);
  535.     } else if (theEntry->fMode == kVRPlay_LoopPalindrome) {
  536.         // start the movie playing in a palindrome loop
  537.         VRMoov_LoopEmbeddedMovie(myMovie, true);
  538.     } else if (theEntry->fMode == kVRPlay_Once) {
  539.         // play the movie once thru
  540.         GoToBeginningOfMovie(myMovie);
  541.         VRMoov_StartMovie(myMovie);
  542.     }
  543.  
  544. bail:
  545.     // we don't want to edit the embedded movie, so we can close the movie file
  546.     if (myMovieFileRef != 0)
  547.         CloseMovieFile(myMovieFileRef);
  548.         
  549.     HUnlock((Handle)myAppData);
  550.  
  551.     return(myErr == noErr);
  552. }
  553.     
  554.     
  555. //////////
  556. //
  557. // VRMoov_LoopEmbeddedMovie
  558. // Start the QuickTime movie playing in a loop.
  559. //
  560. //////////
  561.  
  562. void VRMoov_LoopEmbeddedMovie (Movie theMovie, Boolean isPalindrome)
  563. {
  564.     TimeBase        myTimeBase;
  565.     long             myFlags = 0L;
  566.  
  567.     // set the movie's play hints to enhance looping performance
  568.     SetMoviePlayHints(theMovie, hintsLoop, hintsLoop);
  569.     
  570.     // set the looping flag of the movie's time base
  571.     myTimeBase = GetMovieTimeBase(theMovie);
  572.     myFlags = GetTimeBaseFlags(myTimeBase);
  573.     myFlags |= loopTimeBase;
  574.     
  575.     // set or clear the palindrome flag, depending on the specified setting
  576.     if (isPalindrome)
  577.         myFlags |= palindromeLoopTimeBase;
  578.     else
  579.         myFlags &= ~palindromeLoopTimeBase;
  580.         
  581.     SetTimeBaseFlags(myTimeBase, myFlags);
  582.  
  583.     // start playing the movie
  584.     VRMoov_StartMovie(theMovie);
  585. }
  586.     
  587.  
  588. //////////
  589. //
  590. // VRMoov_DoIdle
  591. // Do any movie-related processing that can or should occur at idle time.
  592. // Returns true if the caller should call QTVRUpdate, false otherwise.
  593. //
  594. //////////
  595.  
  596. Boolean VRMoov_DoIdle (WindowObject theWindowObject)
  597. {
  598.     ApplicationDataHdl        myAppData;
  599.     VRScriptMoviePtr        myPointer;
  600.     Boolean                    myNeedUpdate = false;
  601.  
  602.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  603.     if (myAppData == NULL)
  604.         return(myNeedUpdate);
  605.     
  606.     // walk the linked list and service any embedded sound-only movies
  607.     myPointer = (VRScriptMoviePtr)(**myAppData).fListArray[kVREntry_QTMovie];
  608.     while (myPointer != NULL) {
  609.         if (myPointer->fQTMovieHasSound && !(myPointer->fQTMovieHasVideo)) {
  610.             MoviesTask(myPointer->fMovie, 0L);
  611.         }
  612.         myPointer = myPointer->fNextEntry;
  613.     }
  614.     
  615.     // now service the (single) embedded video movie, if there is one    
  616.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  617.     if (myPointer != NULL) {
  618.         // trip the back buffer procedure, which internally calls MoviesTask;
  619.         // note that this is necessary *only* if the window containing the embedded movie
  620.         // isn't the frontmost window
  621.         if ((**theWindowObject).fWindow != GetFrontAppWindow())
  622.             myNeedUpdate = true;
  623.     }
  624.     
  625.     return(myNeedUpdate);
  626. }
  627.         
  628.                 
  629. //////////
  630. //
  631. // VRMoov_DumpNodeMovies
  632. // Stop playing all movies enlisted for the current node.
  633. //
  634. //////////
  635.  
  636. void VRMoov_DumpNodeMovies (WindowObject theWindowObject)
  637. {
  638.     VRMoov_DumpSelectedMovies(theWindowObject, kVRSelect_Node);
  639. }
  640.  
  641.  
  642. //////////
  643. //
  644. // VRMoov_DumpSceneMovies
  645. // Stop playing all movies enlisted for the current scene.
  646. //
  647. //////////
  648.  
  649. void VRMoov_DumpSceneMovies (WindowObject theWindowObject)
  650. {
  651.     VRMoov_DumpSelectedMovies(theWindowObject, kVRSelect_Scene);
  652. }
  653.  
  654.  
  655. //////////
  656. //
  657. // VRMoov_DumpSelectedMovies
  658. // Stop any existing embedded movies from playing and then clean up.
  659. //
  660. //////////
  661.  
  662. void VRMoov_DumpSelectedMovies (WindowObject theWindowObject, UInt32 theOptions)
  663. {
  664.     ApplicationDataHdl        myAppData;
  665.     VRScriptMoviePtr        myPointer;
  666.     VRScriptMoviePtr        myNext;
  667.  
  668.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  669.     if (myAppData == NULL)
  670.         return;
  671.  
  672.     // walk the movie list and dump any movies movies associated with this node
  673.     myPointer = (VRScriptMoviePtr)(**myAppData).fListArray[kVREntry_QTMovie];
  674.     while (myPointer != NULL) {
  675.         
  676.         myNext = myPointer->fNextEntry;
  677.         if (((myPointer->fNodeID != kVRAnyNode) && (theOptions == kVRSelect_Node)) ||
  678.             ((myPointer->fNodeID == kVRAnyNode) && (theOptions == kVRSelect_Scene)))
  679.             VRScript_DelistEntry(theWindowObject, (VRScriptGenericPtr)myPointer);
  680.         
  681.         myPointer = myNext;
  682.     }
  683.     
  684.     // clear the existing back buffer imaging proc
  685.     QTVRSetBackBufferImagingProc((**theWindowObject).fInstance, NULL, 0, NULL, 0);
  686.  
  687.     // make sure the back buffer is clean
  688.     QTVRRefreshBackBuffer((**theWindowObject).fInstance, 0);
  689.  
  690.     return;
  691. }
  692.     
  693.  
  694. //////////
  695. //
  696. // VRMoov_GetEmbeddedVideo
  697. // Return the first embedded QuickTime movie that has a video track.
  698. //
  699. //////////
  700.  
  701. VRScriptMoviePtr VRMoov_GetEmbeddedVideo (WindowObject theWindowObject)
  702. {
  703.     ApplicationDataHdl        myAppData;
  704.     VRScriptMoviePtr        myPointer = NULL;
  705.     
  706.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  707.     if (myAppData == NULL)
  708.         return(myPointer);
  709.         
  710.     // walk our linked list of movies to find the target movie
  711.     myPointer = (VRScriptMoviePtr)(**myAppData).fListArray[kVREntry_QTMovie];
  712.     while (myPointer != NULL) {
  713.         if (myPointer->fQTMovieHasVideo)
  714.             return(myPointer);
  715.         myPointer = myPointer->fNextEntry;
  716.     }
  717.     
  718.     return(NULL);
  719. }
  720.  
  721.  
  722. //////////
  723. //
  724. // VRMoov_GetEmbeddedMovieWidth
  725. // Get the width of the embedded movie.
  726. //
  727. //////////
  728.  
  729. float VRMoov_GetEmbeddedMovieWidth (WindowObject theWindowObject)
  730. {
  731.     float                    myWidth = 0.0;
  732.     VRScriptMoviePtr        myPointer;
  733.     
  734.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  735.     if (myPointer != NULL)
  736.         myWidth = myPointer->fMovieWidth;
  737.             
  738.     return(myWidth);
  739. }
  740.  
  741.  
  742. //////////
  743. //
  744. // VRMoov_SetEmbeddedMovieWidth
  745. // Set the width of the embedded movie.
  746. //
  747. //////////
  748.  
  749. void VRMoov_SetEmbeddedMovieWidth (WindowObject theWindowObject, float theWidth)
  750. {
  751.     QTVRInstance            myInstance;
  752.     VRScriptMoviePtr        myPointer;
  753.     
  754.     if (theWindowObject == NULL)
  755.         return;
  756.         
  757.     myInstance = (**theWindowObject).fInstance;
  758.     if (myInstance == NULL)
  759.         return;
  760.     
  761.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  762.     if (myPointer != NULL)
  763.         myPointer->fMovieWidth = theWidth;
  764.  
  765.     // clear out the existing area of interest
  766.     QTVRRefreshBackBuffer(myInstance, 0);
  767.  
  768.     // reinstall the back buffer imaging procedure
  769.     VRScript_InstallBackBufferImagingProc(myInstance, theWindowObject);
  770. }
  771.  
  772.  
  773. //////////
  774. //
  775. // VRMoov_GetEmbeddedMovieCenter
  776. // Get the center of the embedded movie.
  777. //
  778. //////////
  779.  
  780. void VRMoov_GetEmbeddedMovieCenter (WindowObject theWindowObject, QTVRFloatPoint *theCenter)
  781. {
  782.     VRScriptMoviePtr        myPointer;
  783.     
  784.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  785.     if (myPointer == NULL) {
  786.         theCenter->x = 0.0;
  787.         theCenter->y = 0.0;
  788.     } else {
  789.         theCenter->x = myPointer->fMovieCenter.x;
  790.         theCenter->y = myPointer->fMovieCenter.y;
  791.     }        
  792. }
  793.  
  794.  
  795. //////////
  796. //
  797. // VRMoov_SetEmbeddedMovieCenter
  798. // Set the center of the embedded movie.
  799. //
  800. //////////
  801.  
  802. void VRMoov_SetEmbeddedMovieCenter (WindowObject theWindowObject, const QTVRFloatPoint *theCenter)
  803. {
  804.     QTVRInstance            myInstance;
  805.     float                    myX, myY;
  806.     VRScriptMoviePtr        myPointer;
  807.  
  808.     if (theWindowObject == NULL)
  809.         return;
  810.         
  811.     myInstance = (**theWindowObject).fInstance;
  812.     if (myInstance == NULL)
  813.         return;
  814.     
  815.     myX = theCenter->x;
  816.     myY = theCenter->y;
  817.     
  818.     // subject the values passed in to the current view constraints
  819.     QTVRWrapAndConstrain(myInstance, kQTVRPan, myX, &myX);
  820.     QTVRWrapAndConstrain(myInstance, kQTVRTilt, myY, &myY);
  821.             
  822.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  823.     if (myPointer != NULL) {
  824.         myPointer->fMovieCenter.x = myX;
  825.         myPointer->fMovieCenter.y = myY;
  826.     }
  827.     
  828.     // clear out the existing area of interest
  829.     QTVRRefreshBackBuffer(myInstance, 0);
  830.  
  831.     // reinstall the back buffer imaging procedure
  832.     VRScript_InstallBackBufferImagingProc(myInstance, theWindowObject);
  833. }
  834.  
  835.  
  836. //////////
  837. //
  838. // VRMoov_GetEmbeddedMovieScale
  839. // Get the scale of the embedded movie.
  840. //
  841. //////////
  842.  
  843. float VRMoov_GetEmbeddedMovieScale (WindowObject theWindowObject)
  844. {
  845.     float                    myScale;
  846.     VRScriptMoviePtr        myPointer;
  847.     
  848.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  849.     if (myPointer == NULL)
  850.         myScale = 0.0;
  851.     else
  852.         myScale = myPointer->fMovieScale;
  853.  
  854.     return(myScale);
  855. }
  856.  
  857.  
  858. //////////
  859. //
  860. // VRMoov_SetEmbeddedMovieScale
  861. // Set the scale factor of the embedded movie.
  862. //
  863. //////////
  864.  
  865. void VRMoov_SetEmbeddedMovieScale (WindowObject theWindowObject, float theScale)
  866. {
  867.     QTVRInstance            myInstance;
  868.     VRScriptMoviePtr        myPointer;
  869.  
  870.     if (theWindowObject == NULL)
  871.         return;
  872.         
  873.     myInstance = (**theWindowObject).fInstance;
  874.     if (myInstance == NULL)
  875.         return;
  876.     
  877.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  878.     if (myPointer != NULL)
  879.         myPointer->fMovieScale = theScale;
  880.     
  881.     // clear out the existing area of interest
  882.     QTVRRefreshBackBuffer(myInstance, 0);
  883.  
  884.     // reinstall the back buffer imaging procedure
  885.     VRScript_InstallBackBufferImagingProc(myInstance, theWindowObject);
  886. }
  887.  
  888.  
  889. //////////
  890. //
  891. // VRMoov_GetEmbeddedMovieRect
  892. // Get the rectangle of the embedded movie.
  893. //
  894. //////////
  895.  
  896. void VRMoov_GetEmbeddedMovieRect (WindowObject theWindowObject, Rect *theRect)
  897. {
  898.     VRScriptMoviePtr        myPointer;
  899.     
  900.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  901.     if (myPointer == NULL) {
  902.         theRect->left = 0.0;
  903.         theRect->top = 0.0;
  904.         theRect->right = 0.0;
  905.         theRect->bottom = 0.0;
  906.     } else {
  907.         theRect->left = myPointer->fMovieBox.left;
  908.         theRect->top = myPointer->fMovieBox.top;
  909.         theRect->right = myPointer->fMovieBox.right;
  910.         theRect->bottom = myPointer->fMovieBox.bottom;
  911.     }        
  912. }
  913.  
  914.  
  915. //////////
  916. //
  917. // VRMoov_SetEmbeddedMovieRect
  918. // Set the rectangle of the embedded movie.
  919. //
  920. //////////
  921.  
  922. void VRMoov_SetEmbeddedMovieRect (WindowObject theWindowObject, const Rect *theRect)
  923. {
  924.     QTVRInstance            myInstance;
  925.     VRScriptMoviePtr        myPointer;
  926.  
  927.     if (theWindowObject == NULL)
  928.         return;
  929.         
  930.     myInstance = (**theWindowObject).fInstance;
  931.     if (myInstance == NULL)
  932.         return;
  933.     
  934.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  935.     if (myPointer != NULL) {
  936.         myPointer->fMovieBox.right = theRect->right;
  937.         myPointer->fMovieBox.bottom = theRect->bottom;
  938.     }
  939.  
  940.     // clear out the existing area of interest
  941.     QTVRRefreshBackBuffer(myInstance, 0);
  942.  
  943.     // reinstall the back buffer imaging procedure
  944.     VRScript_InstallBackBufferImagingProc(myInstance, theWindowObject);
  945. }
  946.  
  947.  
  948. //////////
  949. //
  950. // VRMoov_SetAllBalanceAndVolume
  951. // Set the balance and volume attenuation of all embedded QuickTime movies making sound.
  952. //
  953. //////////
  954.  
  955. void VRMoov_SetAllBalanceAndVolume (WindowObject theWindowObject, float thePan, float theTilt)
  956. {
  957.     ApplicationDataHdl        myAppData;
  958.     VRScriptMoviePtr        myPointer;
  959.     VRScript3DObjPtr        my3DObjPtr;
  960.     
  961.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  962.     if (myAppData == NULL)
  963.         return;
  964.  
  965.     // walk our linked list of embedded QuickTime movies and set the balance and volume of any localized sounds
  966.     myPointer = (VRScriptMoviePtr)(**myAppData).fListArray[kVREntry_QTMovie];
  967.     while (myPointer != NULL) {
  968.         if (myPointer->fQTMovieHasSound)
  969.             if (myPointer->fSoundIsLocalized)
  970.                 VRMoov_SetOneBalanceAndVolume(myPointer->fMovie, myPointer->fMediaHandler, thePan, theTilt, myPointer->fMovieCenter.x, myPointer->fVolAngle);
  971.         myPointer = myPointer->fNextEntry;
  972.     }
  973.     
  974.     // walk our linked list of 3D objects and set the balance and volume of any texture-mapped movies
  975.     my3DObjPtr = (VRScript3DObjPtr)(**myAppData).fListArray[kVREntry_QD3DObject];
  976.     while (my3DObjPtr != NULL) {
  977.         if (my3DObjPtr->fTexture != NULL)
  978.             if (my3DObjPtr->fTextureIsMovie)
  979.                 if ((**my3DObjPtr->fTexture).fMediaHandler != NULL)
  980.                     VRMoov_SetOneBalanceAndVolume((**my3DObjPtr->fTexture).fMovie, (**my3DObjPtr->fTexture).fMediaHandler, thePan, theTilt, QTVRUtils_Point3DToPanAngle(-1.0 * my3DObjPtr->fGroupCenter.x, my3DObjPtr->fGroupCenter.y, -1.0 * my3DObjPtr->fGroupCenter.z), QTVRUtils_DegreesToRadians(kVR_TextureMovieVolAngle));
  981.         my3DObjPtr = my3DObjPtr->fNextEntry;
  982.     }
  983.     
  984. }
  985.     
  986.     
  987. //////////
  988. //
  989. // VRMoov_SetOneBalanceAndVolume
  990. // Set the balance and volume attenuation of an embedded QuickTime movie.
  991. //
  992. //////////
  993.  
  994. void VRMoov_SetOneBalanceAndVolume (Movie theMovie, MediaHandler theMediaHandler, float thePan, float theTilt, float theMoviePan, float theVolAngle)
  995. {
  996. #pragma unused(theTilt)
  997.  
  998.     short            myValue;
  999.     float            myPanDelta;
  1000.     float            myCosDelta;            // cosine of pan angle delta from movie center
  1001.     float            myCosLimit;            // cosine of attenuation cone limit angle
  1002.     
  1003.     myPanDelta = thePan - theMoviePan;
  1004.  
  1005.     // ***set the balance
  1006.     myValue = kQTMaxSoundVolume * sin(myPanDelta);
  1007.     MediaSetSoundBalance(theMediaHandler, myValue);
  1008.     
  1009.     // ***set the volume
  1010.     myCosDelta = cos(myPanDelta);
  1011.     myCosLimit = cos(theVolAngle);
  1012.  
  1013.     if (myCosDelta >= myCosLimit)
  1014.         // inside cone of attenuation, volume scales from 1.0 (at center) to 0.0 (at cone edge)
  1015.         myValue = kQTMaxSoundVolume * ((myCosDelta - myCosLimit) / (1 - myCosLimit));
  1016.     else
  1017.         // outside cone of attenuation, volume is 0.0;
  1018.         myValue = kNoVolume;
  1019.     
  1020.     if (myValue != GetMovieVolume(theMovie))
  1021.         SetMovieVolume(theMovie, myValue);
  1022. }
  1023.  
  1024.  
  1025. //////////
  1026. //
  1027. // VRMoov_CalcImagingMatrix
  1028. // Calculate the movie matrix required to draw the embedded movie into the specified rectangle.
  1029. //
  1030. //////////
  1031.  
  1032. OSErr VRMoov_CalcImagingMatrix (WindowObject theWindowObject, Rect *theBBufRect)
  1033. {
  1034.     ApplicationDataHdl        myAppData = NULL;
  1035.     VRScriptMoviePtr        myPointer = NULL;
  1036.     Rect                    myDestRect = *theBBufRect;
  1037.  
  1038.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  1039.     if (myAppData == NULL) 
  1040.         return(paramErr);
  1041.         
  1042.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  1043.     if (myPointer == NULL) 
  1044.         return(paramErr);
  1045.  
  1046.     // reset the current movie matrix with the original movie matrix of the embedded movie;
  1047.     // we need to preserve that matrix in our calculations below if we are not drawing the
  1048.     // movie into an offscreen GWorld
  1049.     myPointer->fMovieMatrix = myPointer->fOrigMovieMatrix;
  1050.     
  1051.     // in general, it's easiest to construct the desired matrix by first doing the scaling
  1052.     // and then doing the rotation and translation (if necessary); so we need to swap the
  1053.     // right and bottom edges of the back buffer rectangle before doing the scaling, if a
  1054.     // rotation will also be necessary
  1055.     if (!(**myAppData).fBackBufferIsHoriz) {
  1056.         myDestRect.bottom = theBBufRect->right;
  1057.         myDestRect.right = theBBufRect->bottom;
  1058.     }
  1059.     
  1060.     // set up the scaling matrix
  1061.     // (MapMatrix concatenates the new matrix to the existing matrix, whereas RectMatrix first
  1062.     // sets the existing matrix to the identity matrix)
  1063.     if (myPointer->fUseOffscreenGWorld)
  1064.         RectMatrix(&myPointer->fMovieMatrix, &myPointer->fMovieBox, &myDestRect);
  1065.     else
  1066.         MapMatrix(&myPointer->fMovieMatrix, &myPointer->fMovieBox, &myDestRect);
  1067.  
  1068.     // add a rotation and translation, if necessary (and if requested to do so)
  1069.     if (!(**myAppData).fBackBufferIsHoriz)
  1070.         if (myPointer->fDoRotateMovie) {
  1071.             RotateMatrix(&myPointer->fMovieMatrix, Long2Fix(-90), 0, 0);
  1072.             TranslateMatrix(&myPointer->fMovieMatrix, 0, Long2Fix(RECT_HEIGHT(*theBBufRect)));
  1073.         }
  1074.  
  1075.     return(noErr);
  1076. }
  1077.  
  1078.  
  1079. //////////
  1080. //
  1081. // VRMoov_SetupDecompSeq
  1082. // Set up the decompression sequence for DecompressionSequenceFrameS.
  1083. //
  1084. // This needs to be called whenever either the rectangle or the GWorld of the back buffer changes.
  1085. //
  1086. //////////
  1087.  
  1088. OSErr VRMoov_SetupDecompSeq (VRScriptMoviePtr theEntry, GWorldPtr theDestGWorld)
  1089. {
  1090.     short                    myMode = srcCopy;
  1091.     OSErr                    myErr = noErr;
  1092.     
  1093.     if (theEntry == NULL) 
  1094.         return(paramErr);
  1095.  
  1096.     // make sure we don't have a decompression sequence already open
  1097.     VRMoov_RemoveDecompSeq(theEntry);
  1098.     
  1099.     // set up the transfer mode
  1100.     if (theEntry->fCompositeMovie)
  1101.         myMode = srcCopy | transparent;
  1102.         
  1103.     // set up the image decompression sequence
  1104.     myErr = DecompressSequenceBegin(    &theEntry->fImageSequence,
  1105.                                         theEntry->fImageDesc,
  1106.                                         (CGrafPtr)theDestGWorld,
  1107.                                         NULL,
  1108.                                         NULL,                            // entire source image
  1109.                                         &theEntry->fMovieMatrix,
  1110.                                            myMode,
  1111.                                         NULL,                            // no mask
  1112.                                         0,
  1113.                                         (**(theEntry->fImageDesc)).spatialQuality,
  1114.                                         NULL);
  1115.                                     
  1116.     return(myErr);
  1117. }
  1118.  
  1119.  
  1120. //////////
  1121. //
  1122. // VRMoov_RemoveDecompSeq
  1123. // Remove the decompression sequence for DecompressionSequenceFrameS.
  1124. //
  1125. //////////
  1126.  
  1127. OSErr VRMoov_RemoveDecompSeq (VRScriptMoviePtr theEntry)
  1128. {
  1129.     OSErr                    myErr = paramErr;
  1130.     
  1131.     if (theEntry != NULL) 
  1132.         if (theEntry->fImageSequence != 0) {
  1133.             myErr = CDSequenceEnd(theEntry->fImageSequence);
  1134.             theEntry->fImageSequence = 0;
  1135.         }
  1136.     
  1137.     return(myErr);
  1138. }
  1139.  
  1140.  
  1141. //////////
  1142. //
  1143. // VRMoov_BackBufferImagingProc
  1144. // The back buffer imaging procedure:
  1145. //    * get a frame of movie and image it into the back buffer
  1146. //    * also, do any additional compositing that might be desired
  1147. // This function is called by VRScript_BackBufferImagingProc.
  1148. //
  1149. //////////
  1150.  
  1151. PASCAL_RTN OSErr VRMoov_BackBufferImagingProc (QTVRInstance theInstance, Rect *theRect, UInt16 theAreaIndex, UInt32 theFlagsIn, UInt32 *theFlagsOut, WindowObject theWindowObject)
  1152. {
  1153. #pragma unused(theAreaIndex)
  1154.  
  1155.     ApplicationDataHdl        myAppData = NULL;
  1156.     Movie                    myMovie = NULL;
  1157.     Boolean                    myIsDrawing = theFlagsIn & kQTVRBackBufferRectVisible;
  1158.     VRScriptMoviePtr        myPointer = NULL;
  1159.     GWorldPtr                myBBufGWorld, myMovGWorld;
  1160.     GDHandle                myBBufGDevice, myMovGDevice;
  1161.     Rect                    myRect;
  1162.     OSErr                    myErr = paramErr;
  1163.     
  1164.     //////////
  1165.     //
  1166.     // initialize; make sure that we've got the data we need to continue
  1167.     //
  1168.     //////////
  1169.  
  1170.     // assume we're not going to draw anything
  1171.     *theFlagsOut = 0;
  1172.     
  1173.     if ((theInstance == NULL) || (theWindowObject == NULL)) 
  1174.         return(paramErr);
  1175.  
  1176.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  1177.     if (myAppData == NULL) 
  1178.         return(paramErr);
  1179.  
  1180.     myPointer = VRMoov_GetEmbeddedVideo(theWindowObject);
  1181.     if (myPointer == NULL)
  1182.         return(paramErr);
  1183.         
  1184.     HLock((Handle)myAppData);
  1185.  
  1186.     myMovie = myPointer->fMovie;
  1187.     if ((myMovie == NULL) || (IsMovieDone(myMovie))) {
  1188.         // we don't have an embedded movie, or it's done playing, so remove this back-buffer imaging procedure
  1189.         QTVRSetBackBufferImagingProc((**theWindowObject).fInstance, NULL, 0, NULL, 0);
  1190.         goto bail;
  1191.     }
  1192.     
  1193.     //////////
  1194.     //
  1195.     // make sure that the movie GWorld is set correctly;
  1196.     // note that we call SetMovieGWorld only if we have to (for performance reasons)
  1197.     //
  1198.     //////////
  1199.     
  1200.     // get the current graphics world
  1201.     // (on entry, the current graphics world is [usually] set to the back buffer)
  1202.     GetGWorld(&myBBufGWorld, &myBBufGDevice);
  1203.  
  1204.     // get the embedded movie's graphics world
  1205.     GetMovieGWorld(myMovie, &myMovGWorld, &myMovGDevice);
  1206.  
  1207.     if (myPointer->fUseOffscreenGWorld) {
  1208.         // we're using an offscreen graphics world, so set movie's GWorld to be that offscreen graphics world
  1209.         if (myMovGWorld != myPointer->fOffscreenGWorld)
  1210.             SetMovieGWorld(myMovie, myPointer->fOffscreenGWorld, GetGWorldDevice(myPointer->fOffscreenGWorld));            
  1211.     } else {
  1212.         // we're not using an offscreen graphics world, so set movie GWorld to be the back buffer;
  1213.         if ((myMovGWorld != myBBufGWorld) || (myMovGDevice != myBBufGDevice))
  1214.             SetMovieGWorld(myMovie, myBBufGWorld, myBBufGDevice);
  1215.     }
  1216.  
  1217.     //////////
  1218.     //
  1219.     // make sure the movie rectangle and movie matrix are set correctly
  1220.     //
  1221.     //////////
  1222.     
  1223.     if (myIsDrawing) {
  1224.         // if we weren't previously visible, make sure we are now
  1225.         GetMovieBox(myMovie, &myRect);
  1226.         if (EmptyRect(&myRect))
  1227.             SetMovieBox(myMovie, &myPointer->fMovieBox);
  1228.         
  1229.         // when no offscreen GWorld is being used...
  1230.         if (!myPointer->fUseOffscreenGWorld) {
  1231.             
  1232.             // ...make sure the movie matrix is set correctly...
  1233.             if (!MacEqualRect(theRect, &myPointer->fPrevBBufRect)) {
  1234.                 VRMoov_CalcImagingMatrix(theWindowObject, theRect);
  1235.                 SetMovieMatrix(myMovie, &myPointer->fMovieMatrix);
  1236.             }
  1237.             
  1238.             // ...and, if we are compositing, force QuickTime to draw a movie frame when MoviesTask is called
  1239.             // (since the previous frame was automatically erased from the back buffer by QuickTime VR)
  1240.             if (myPointer->fCompositeMovie)
  1241.                 UpdateMovie(myMovie);
  1242.         }
  1243.         
  1244.     } else {
  1245.         // if we're not visible, set the movie rectangle to an empty rectangle
  1246.         // so we're not wasting time trying to draw a movie frame
  1247.         MacSetRect(&myRect, 0, 0, 0, 0);
  1248.         SetMovieBox(myMovie, &myRect);
  1249.     }
  1250.  
  1251.     //////////
  1252.     //
  1253.     // draw a new movie frame into the movie's graphics world (and play movie sound)
  1254.     //
  1255.     //////////
  1256.     
  1257.     MoviesTask(myMovie, 0);
  1258.     
  1259.     // if we got here, everything is okay so far
  1260.     myErr = noErr;
  1261.  
  1262.     //////////
  1263.     //
  1264.     // perform any additional compositing
  1265.     //
  1266.     //////////
  1267.     
  1268.     // that is, draw, using the current chroma key color, anything to be dropped out of the image;
  1269.     // note that this technique works *only* if we're using an offscreen graphics world
  1270.     if (myPointer->fUseOffscreenGWorld && myPointer->fCompositeMovie && myIsDrawing) {
  1271.         RGBColor    myColor;
  1272.     
  1273.         // since we're using an offscreen graphics world, make sure we draw there
  1274.         SetGWorld(myPointer->fOffscreenGWorld, GetGWorldDevice(myPointer->fOffscreenGWorld));
  1275.  
  1276.         // set up compositing environment
  1277.         GetForeColor(&myColor);
  1278.         RGBForeColor(&myPointer->fChromaColor);
  1279.         
  1280.         // do the drawing
  1281.         if (myPointer->fHideRegion != NULL)
  1282.             MacPaintRgn(myPointer->fHideRegion);
  1283.             
  1284.         // restore original drawing environment
  1285.         RGBForeColor(&myColor);
  1286.         
  1287.         // restore original graphics world
  1288.         SetGWorld(myBBufGWorld, myBBufGDevice);
  1289.     }
  1290.  
  1291.     //////////
  1292.     //
  1293.     // if we're using an offscreen graphics world, copy it into the back buffer
  1294.     //
  1295.     //////////
  1296.     
  1297.     if (myIsDrawing) {
  1298.     
  1299.         if (myPointer->fUseOffscreenGWorld) {
  1300.             PixMapHandle    myPixMap;
  1301.             
  1302.             // if anything relevant to DecompressSequenceFrameS has changed, reset the decompression sequence
  1303.             if ((myBBufGWorld != myPointer->fPrevBBufGWorld) || !(MacEqualRect(theRect, &myPointer->fPrevBBufRect))) {
  1304.                 VRMoov_CalcImagingMatrix(theWindowObject, theRect);
  1305.                 VRMoov_SetupDecompSeq(myPointer, myBBufGWorld);
  1306.             }
  1307.             
  1308.             myPixMap = GetGWorldPixMap(myPointer->fOffscreenGWorld);
  1309.             LockPixels(myPixMap);
  1310.             
  1311.             // set the chroma key color, if necessary
  1312.             if (myPointer->fCompositeMovie)
  1313.                 RGBBackColor(&myPointer->fChromaColor);
  1314.             
  1315.             // copy the image from the offscreen graphics world into the back buffer
  1316.             myErr = DecompressSequenceFrameS(    myPointer->fImageSequence,
  1317.                                                 StripAddress(GetPixBaseAddr(myPixMap)),
  1318.                                                 (**(myPointer->fImageDesc)).dataSize,
  1319.                                                 0,
  1320.                                                 NULL,
  1321.                                                 NULL);
  1322.  
  1323.             // reset the chroma key color;
  1324.             // we need to do this because the buffer we just drew into might NOT actually
  1325.             // be the real back buffer (see Virtual Reality Programming With QuickTime VR, p. 1-154);
  1326.             // the copy between the intermediate buffer and the back buffer respects the current back color.
  1327.             if (myPointer->fCompositeMovie)
  1328.                 RGBBackColor(&kWhiteColor);
  1329.                 
  1330.             UnlockPixels(myPixMap);
  1331.         }
  1332.     }
  1333.     
  1334.     //////////
  1335.     //
  1336.     // finish up
  1337.     //
  1338.     //////////
  1339.     
  1340.     // keep track of the GWorld and rectangle passed to us this time
  1341.     myPointer->fPrevBBufGWorld = myBBufGWorld;
  1342.     myPointer->fPrevBBufRect = *theRect;
  1343.     
  1344.     // if we drew something, tell QuickTime VR
  1345.     if (myIsDrawing)
  1346.         *theFlagsOut = kQTVRBackBufferFlagDidDraw;
  1347.     
  1348. bail:    
  1349.     HUnlock((Handle)myAppData);
  1350.     return(myErr);
  1351. }
  1352.  
  1353.  
  1354. //////////
  1355. //
  1356. // VRMoov_CoverProc
  1357. // The cover function of the embedded movie.
  1358. //
  1359. //////////
  1360.  
  1361. PASCAL_RTN OSErr VRMoov_CoverProc (Movie theMovie, RgnHandle theRegion, WindowObject theWindowObject)
  1362. {
  1363. #pragma unused(theMovie, theRegion, theWindowObject)
  1364.  
  1365.     return(noErr);
  1366. }
  1367.  
  1368.  
  1369. //////////
  1370. //
  1371. // VRMoov_SetVideoGraphicsMode
  1372. // Set the video media graphics mode of the embedded movie.
  1373. //
  1374. //////////
  1375.  
  1376. void VRMoov_SetVideoGraphicsMode (Movie theMovie, VRScriptMoviePtr theEntry, Boolean theSetVGM)
  1377. {
  1378.     Track        myTrack;
  1379.     Media        myMedia;
  1380.  
  1381.     if (theEntry == NULL)
  1382.         return;
  1383.         
  1384.     myTrack = GetMovieIndTrackType(theMovie, 1, VideoMediaType, movieTrackMediaType | movieTrackEnabledOnly);
  1385.     if (myTrack != NULL) {
  1386.         myMedia = GetTrackMedia(myTrack);
  1387.         if (theSetVGM)
  1388.             MediaSetGraphicsMode(GetMediaHandler(myMedia), srcCopy | transparent, &theEntry->fChromaColor);
  1389.         else
  1390.             MediaSetGraphicsMode(GetMediaHandler(myMedia), srcCopy, &kWhiteColor);
  1391.     } 
  1392.         
  1393.     return;
  1394. }
  1395.  
  1396.  
  1397. //////////
  1398. //
  1399. // VRMoov_GetFinishedMovie
  1400. // Get the first enlisted movie that is done playing.
  1401. //
  1402. //////////
  1403.  
  1404. VRScriptMoviePtr VRMoov_GetFinishedMovie (WindowObject theWindowObject)
  1405. {
  1406.     ApplicationDataHdl    myAppData;
  1407.     VRScriptMoviePtr    myPointer = NULL;
  1408.  
  1409.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);    
  1410.     if (myAppData == NULL)
  1411.         return(NULL);
  1412.     
  1413.     // walk our linked list of movies to find the target movie
  1414.     myPointer = (VRScriptMoviePtr)(**myAppData).fListArray[kVREntry_QTMovie];
  1415.     while (myPointer != NULL) {
  1416.         if (IsMovieDone(myPointer->fMovie))
  1417.             return(myPointer);
  1418.         
  1419.         myPointer = myPointer->fNextEntry;
  1420.     }
  1421.     
  1422.     return(NULL);
  1423. }
  1424.  
  1425.  
  1426. //////////
  1427. //
  1428. // VRMoov_CheckForCompletedMovies
  1429. // Clean up any movies that are finished playing.
  1430. //
  1431. //////////
  1432.  
  1433. void VRMoov_CheckForCompletedMovies (WindowObject theWindowObject)
  1434. {
  1435.     VRScriptMoviePtr        myPointer = NULL;
  1436.     
  1437.     // delist any completed movies for the specified movie window
  1438.     if (theWindowObject != NULL)
  1439.         while ((myPointer = VRMoov_GetFinishedMovie(theWindowObject)) != NULL)
  1440.             VRScript_DelistEntry(theWindowObject, (VRScriptGenericPtr)myPointer);
  1441. }
  1442.  
  1443.  
  1444. //////////
  1445. //
  1446. // VRMoov_DumpEntryMem
  1447. // Release any memory associated with the specified list entry.
  1448. //
  1449. //////////
  1450.  
  1451. void VRMoov_DumpEntryMem (VRScriptMoviePtr theEntry)
  1452. {
  1453.     if (theEntry != NULL) {
  1454.         
  1455.         if (theEntry->fMovie != NULL) {
  1456.             StopMovie(theEntry->fMovie);
  1457.             DisposeMovie(theEntry->fMovie);
  1458.         }
  1459.             
  1460.         if (theEntry->fQTMovieHasVideo) {
  1461.             if (theEntry->fOffscreenPixMap != NULL)
  1462.                 UnlockPixels(theEntry->fOffscreenPixMap);
  1463.                 
  1464.             if (theEntry->fOffscreenGWorld != NULL)
  1465.                 DisposeGWorld(theEntry->fOffscreenGWorld);
  1466.                 
  1467.             if (theEntry->fHideRegion != NULL)
  1468.                 DisposeRgn(theEntry->fHideRegion);
  1469.                 
  1470.             VRMoov_RemoveDecompSeq(theEntry);
  1471.             
  1472.             if (theEntry->fImageDesc != NULL)
  1473.                 DisposeHandle((Handle)theEntry->fImageDesc);
  1474.                 
  1475.         }
  1476.         
  1477.         theEntry->fMovie = NULL;
  1478.         theEntry->fOffscreenGWorld = NULL;
  1479.         theEntry->fPrevBBufGWorld = NULL;
  1480.         theEntry->fMediaHandler = NULL;
  1481.         theEntry->fHideRegion = NULL;
  1482.         theEntry->fImageDesc = NULL;
  1483.         
  1484.         free(theEntry->fPathname);
  1485.     }
  1486. }